#include <func.h>
#include"project.h"
#include"threadpool.h"

#define PATH_MLEN 1048         //路径最大长度(mkDir)
//小火车发送
void trainSend(char* buff,int peerfd){
    train_t train;
    train.length = strlen(buff);
    strncpy(train.data,buff,train.length);
    int ret = sendn(peerfd,&train,4+train.length);
    printf("send %d bytes\n",ret);
}

//命令解析实现
void splitChar(char* from, char* operate, char* operand){
    int fromLen = strlen(from);
    int i = 0, j = 0;

    for(i = 0;i<fromLen;i++){
        if(from[i]==' '){
            i++;
            break;
        }else{
            operate[i] = from[i];
        }
    }
    printf("split order is %s\n",operate);

    for(j=0;i<fromLen;j++,i++){
        operand[j]=from[i];
    }
    printf("split filename is %s\n",operand);

}

//命令判断
void judge(char*order,char*filename,int peerfd){
    if(strcmp(order,"rm") == 0){
        printf(">order have rm\n");
        rm(filename,peerfd);
    }else if(strcmp(order,"cd")== 0){
        cd(filename,peerfd);
    }/*else if(strcmp(order,"ls")==0){

       }else if(strcmp(order,"pwd")==0){
       printf("order is pwd\n");
       pwd(peerfd);
       }*/else if(strcmp(order,"puts")==0){
           do_puts(peerfd,filename);
       }/*else if(strcmp(order,"gets")==0){
           trainSend(order,peerfd); 
           do_gets(peerfd,filename);
       }*/else if(strcmp(order,"mkdir")==0){
           printf(">order is mkdir\n");
           mkDir(filename,peerfd);
       }else{
           char buff[100]="erro command";
           trainSend(buff,peerfd);
       }
//return;
}
//删除文件
int rm( char *dir,int peerfd )
{
    printf("enter rm \n");
    char cur_dir[] = ".";
    char up_dir[] = "..";
    char dir_name[128];
    DIR *dirp;
    struct dirent *dp;
    struct stat dir_stat;

    // 参数传递进来的目录不存在，直接返回
    if ( 0 != access(dir, F_OK)   ) {
        printf("filename error\n");

        char buff[100]="filename error";
        trainSend(buff,peerfd);
        // return 0;
    }

    // 获取目录属性失败，返回错误
    if ( 0 > stat(dir, &dir_stat)   ) {
        char buff[100]="get directory stat error";
        trainSend(buff,peerfd);
    }

    if ( S_ISREG(dir_stat.st_mode)   ) {  // 普通文件直接删除
        remove(dir);
    } else if ( S_ISDIR(dir_stat.st_mode)   ) {   // 目录文件，递归删除目录中内容
        dirp = opendir(dir);
        while ( (dp=readdir(dirp)) != NULL   ) {
            // 忽略 . 和 ..
            if ( (0 == strcmp(cur_dir, dp->d_name)) || (0 == strcmp(up_dir, dp->d_name))   ) {
                continue;
            }

            sprintf(dir_name, "%s/%s", dir, dp->d_name);
            rm(dir_name,peerfd);   // 递归调用
        }
        closedir(dirp);

        rmdir(dir);     // 删除空目录
    } else {
        char buff[100]="unknow file type!";
        trainSend(buff,peerfd);
    }

    char buff[100]="rm is success";
    trainSend(buff,peerfd);
}

//创建文件
void mkDir(char *filename,int fd){

    char path[PATH_MLEN];
    getcwd(path, PATH_MLEN);

    printf("mkDir: path = %s\n", path);

    DIR *dir = opendir(path); //打开目录
    ERROR_CHECK(dir, NULL, "opendir");

    struct dirent *pdirent; //目录项指针
    while ((pdirent = readdir(dir)) != NULL)
    {
        if (strcmp(pdirent->d_name, filename) == 0 && pdirent->d_type == DT_DIR) //该文件夹已存在，则创建失败
        {
            char msg[128] = "mkdir faild,this dir has been created.\n";
            trainSend(msg,fd);
            //sendn(fd, msg, strlen(msg));
            closedir(dir);
        }

    }

    char filePath[PATH_MLEN] = {0};
    strcpy(filePath, path);
    strcat(filePath, "/");
    strcat(filePath, filename);

    printf("mkDir: filePath = %s\n", filePath);

    int ret = mkdir(filePath, 0777); //创建文件夹
    ERROR_CHECK(ret, -1, "mkdir");

    char msg[128] = "mkdir success.\n";
    trainSend(msg,fd);
    // sendn(fd, msg, strlen(msg));
    closedir(dir);
}

//ls指令实现
void ls(int sockfd){
    /* DIR* pdir=opendir(dirname);
       char sendll[1000]={0};
       bzero(sendll,1000);
       ERROR_CHECK(pdir,NULL,"opendir");
       chdir(dirname);
       struct dirent* pdirent;
       while((pdirent=readdir(pdir))!=NULL){
    //存储目录信息
    struct stat statbuf;
    //存储时间信息
    struct tm *tmbuf;
    //存储文件类型及权限
    struct filemode mod;
    memset(&mod,0,sizeof(mod));
    transmode(statbuf.st_mode,&mod);
    int ret=stat(pdirent->d_name,&statbuf);
    //tmbuf = localtime(&statbuf.st_mtim);


    sprintf(sendll,"%c %s %3ld %8s %8s %8ld %2d月 %2d %2d:%2d %s\n",
    mod.type,
    mod.power,
    statbuf.st_nlink,
    getpwuid(statbuf.st_uid)->pw_name,
    getgrgid(statbuf.st_gid)->gr_name,
    statbuf.st_size,
    tmbuf->tm_mon,
    tmbuf->tm_mday,
    tmbuf->tm_hour,
    tmbuf->tm_min,
    pdirent->d_name);
    int len=0;
    len=strlen(sendll);
    send(fd,&len,sizeof(int),0);
    sendn(fd,sendll,len);
    }*/

    /*train_t train;
      char *cur_path = getcwd(NULL, 0);
      printf("do_ls cur_path=%s\n", cur_path);
      DIR *pdir = opendir(cur_path);
      struct dirent *pdirent;
      char buf[1024], count = 0;
      while (pdirent = readdir(pdir))
      {
      count = 0;
      memset(buf, 0, sizeof(buf));
      memset(&train, 0, sizeof(train_t));
      if (pdirent->d_name[0] == '.')
      {
      continue;

      }
      if (pdirent->d_type == 4)
      buf[count++] = 'd';
      else if (pdirent->d_type == 8)
      buf[count++] = '-';
      else
      buf[count++] = 'u';
      buf[count++] = ' ';
      strcpy(buf + count, pdirent->d_name);
      train.length = strlen(buf);
      printf("len=%d buf=%s\n", train.length, buf);
      strcpy(train.data, buf);
      sendn(sfd, &train, 4 + train.length);

      }
      memset(&train, 0, sizeof(train));
      train.length = 0;
      sendn(sfd, &train, 4);
      */
    int ret;
    char*cwd=getcwd(NULL,0);
    DIR *dirp=opendir(cwd);
    if(dirp==NULL){
        fprintf(stderr,"open dir:%s failed",cwd);

    }
    struct dirent *pDir=NULL;
    while((pDir=readdir(dirp))!=NULL){
        if(strcmp(pDir->d_name,".")==0||strcmp(pDir->d_name,"..")==0){
            continue;

        }
        else {
            //ret=send(sockfd,pDir->d_name,strlen(pDir->d_name),0);
            //ERROR_CHECK(ret,-1,"send");
            trainSend(pDir->d_name,sockfd);

        }

    }
    free(cwd);
    closedir(dirp);
}
void transmode(mode_t mode,filemode_t* mod)
{
    switch (mode & S_IFMT) {
    case S_IFBLK:  mod->type='b';  break;
    case S_IFCHR:  mod->type='c';    break;
    case S_IFDIR:  mod->type='d';     break;
    case S_IFIFO:  mod->type='p';    break;
    case S_IFLNK:  mod->type='l';   break;
    case S_IFREG:  mod->type='-';   break;
    case S_IFSOCK: mod->type='s';   break;
    default:       mod->type='u';    break;

    }
    int ugo[3]={0};
    for(int i=0;i<3;i++){
        ugo[2-i]=mode&07;
        mode>>=3;

    }
    for(int i=0;i<3;i++){
        switch(ugo[i]){
        case 1: strcpy(&(mod->power[3*i]),"--x");   break;
        case 2: strcpy(&(mod->power[3*i]),"-w-");   break;
        case 3: strcpy(&(mod->power[3*i]),"-wx");  break;
        case 4: strcpy(&(mod->power[3*i]),"r--");   break;
        case 5: strcpy(&(mod->power[3*i]),"r-x");   break;
        case 6: strcpy(&(mod->power[3*i]),"rw-");    break;
        case 7: strcpy(&(mod->power[3*i]),"rwx");    break;
        default:strcpy(&(mod->power[3*i]),"---");    break;

        }

    }

}

//cd命令实现
void cd(char *path ,int sockfd){
    int ret;
    char errbuf[1024]={0};
    char *cwdpath=NULL;
    ret=chdir(path);
    if(-1==ret){
        strerror_r(errno,errbuf,sizeof(errbuf));
        trainSend(errbuf,sockfd);
        /*ret=send(sockfd,errbuf,strlen(errbuf),0);
          ERROR_CHECK(ret,-1,"send");*/
    }
    cwdpath=getcwd(NULL,0);
    if(NULL==cwdpath){
        strerror_r(errno,errbuf,sizeof(errbuf));
        trainSend(errbuf,sockfd);
        /*ret=send(sockfd,errbuf,strlen(errbuf),0);
          ERROR_CHECK(ret,-1,"send");*/
    }
    //发送结果
    trainSend(cwdpath,sockfd);
    /*ret=send(sockfd,cwdpath,strlen(cwdpath),0);
      ERROR_CHECK(ret, -1, "send");*/
}

//pwd命令实现
void pwd(int sockfd){
    printf("enter pwe\n");
    int ret;
    char cwdpath[512];
    char errbuf[1024]={0};
    getcwd(cwdpath,sizeof(cwdpath));
    printf("%s\n",cwdpath);
    /*if(NULL==cwdpath){
      strerror_r(errno,errbuf,sizeof(errbuf));
      trainSend(errbuf,sockfd);
      ret=send(sockfd,errbuf,strlen(errbuf),0);
      ERROR_CHECK(ret,-1,"send");

      }*/
    trainSend(cwdpath,sockfd);

}

//puts命令实现
void do_puts(int sfd, char *cmd)
{
     printf("do_puts is enter\n");
       train_t train;
       memset(&train, 0, sizeof(train));
       recvn(sfd, &train.length, 4);
       printf("train.len=%d\n", train.length);
       if (train.length == -1)
       {
       printf("puts error\n");
       char buff[100]= "puts error";
       trainSend(buff,sfd);
       return;
    }
    recv_file(sfd, cmd);
    

    /*
    printf("---enter recvFile---\n");
    //3. 下载文件
    //3.1 接收文件的名字
    int length;
    int ret = recv(clientfd, &length, 4, MSG_WAITALL);
    printf(">>1. filename length:%d\n", length);

    //提出新的需求: 需要接收确定字节数的数据
    char recvBuff[1000] = {0};//应用层接收缓冲区
    ret = recv(clientfd, recvBuff, length, MSG_WAITALL); printf(">>2. recv filename:%s\n", recvBuff);
    printf("filename is %s\n",recvBuff);

    //3.2 在客户端本地，要创建文件
    int fileFd = open(recvBuff, O_CREAT|O_RDWR, 0644);
    //3.3 接收文件的大小
    off_t fileSize;
    ret = recv(clientfd, &length, 4, MSG_WAITALL);
    printf("length: %d\n", length);
    ret = recv(clientfd, &fileSize, sizeof(fileSize), MSG_WAITALL);
    printf("> file length: %ld\n", fileSize);

    ftruncate(fileFd, fileSize);

    //3.4 接收文件的内容
    char * pbuf = (char*) mmap(NULL, fileSize, 
                               PROT_READ|PROT_WRITE, 
                               MAP_SHARED, fileFd, 0);
    ret = recv(clientfd, pbuf, fileSize, MSG_WAITALL);

    printf("recv file success\n");
    printf("---------------------\n");

    close(fileFd);
    munmap(pbuf, fileSize);
*/

}

void recv_file(int sfd, char *filename)
{
    train_t train;
    memset(&train, 0, sizeof(train));
    printf("start recv_file\n");
    int fd = open(filename, O_CREAT | O_RDWR | O_APPEND, 0666);
    if (fd == -1)
    {
        printf("open error\n");
        char buff[100]="open error";
        trainSend(buff,sfd);
        return;

    }
    memset(&train, 0, sizeof(train));
    off_t filesize;
    recvn(sfd, &train.length ,sizeof(train.length));
    recvn(sfd, &filesize, train.length);
    int left = filesize, cur = 0, ret = 0;
    while (left > 0)
    {
        memset(&train, 0, sizeof(train));
        recvn(sfd, &train.length, 4);
        recvn(sfd, train.data, train.length);
        ret = write(fd, train.data, train.length);
        if (ret == -1)
        {
            printf("write error");
            char buff[100]="write error";
            trainSend(buff,sfd);
            return;

        }
        cur += ret;
        left -= ret;
        printf("letf is %d\n",left);

    }
    char sbuff[100]="recv file success";
    trainSend(sbuff,sfd);
}

//gets 命令实现
void do_gets(int sfd, char *cmd)
{
    send_file(sfd, cmd);

}

void send_file(int sfd, char *filename)
{
    //先判断文件是否存在
    off_t file_exit = 0;
    train_t train;
    memset(&train, 0, sizeof(train_t));
    // recvn(sfd, &train.len, 4);
    //  recvn(sfd, &file_exit, train.len);
    //  printf("file_exit=%ld\n", file_exit);

    memset(&train, 0, sizeof(train_t));
    printf("---filename strlen %d\n",strlen(filename));
    int fd = open(filename, O_RDONLY);
    if (fd == -1)
    {
        printf("puts error\n"); //本地不存在此文件
        train.length = -1;
        sendn(sfd, &train, 4);
        return;
    }
    train.length = 1;
    sendn(sfd, &train, 4);

    struct stat file_status;
    memset(&file_status, 0, sizeof(file_status));
    fstat(fd, &file_status);
    off_t file_size = file_status.st_size - file_exit;
    memset(&train, 0, sizeof(train));
    memcpy(train.data, &file_size, sizeof(file_size));
    train.length = sizeof(file_size);
    sendn(sfd, &train, train.length + 4);

    int ret, left = file_size, cur = 0;
    while (left > 0)
    {
        memset(&train, 0, sizeof(train));
        ret = read(fd, train.data, sizeof(train.data));
        if (ret == 0)
        {
            printf("read error\n");
             return;
        }
        train.length = ret;
        ret = sendn(sfd, &train, 4 + train.length);
        cur += train.length;
        left -= train.length;
    }
    printf("send_file send file success\n");
}



